package com.jason.www.controller;

import com.jason.www.code.XMLUtil;
import com.jason.www.code.impl.WXpayClient;
import com.jason.www.commons.PropertyConfigurer;
import com.jason.www.controller.vo.PayCallbackVo;
import com.jason.www.controller.vo.PayRequestVo;
import com.jason.www.service.IPayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import static com.jason.www.code.impl.NewAlipayClient.TRADE_SUCCESS;
import static com.jason.www.enums.PayType.NEWALIPAY;
import static com.jason.www.enums.PayType.UNIONPAY;
import static com.jason.www.enums.PayType.WXPAY;


/**
 * 整合多个支付方式 通过PayType来区分
 */
@Slf4j
@Controller
@RequestMapping("/pay")
public class PayController {
    @Autowired
    IPayService payService;
    @Autowired
    PropertyConfigurer propertyConfigurer;

    /**
     * 构造支付信息
     * @param request
     * @param response
     * @param payRequestVo
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IOException
     */
    @RequestMapping(value = "/paymsg", method = RequestMethod.POST)
    public void paymsg(HttpServletRequest request, HttpServletResponse response, @RequestBody PayRequestVo payRequestVo) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
        payRequestVo.setRequestUrl(request.getRequestURL().toString().replace(request.getRequestURI(), ""));
        testData(request,payRequestVo);
        String form = payService.constructPayMessage(payRequestVo.getPayType(), BeanUtils.describe(payRequestVo));
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(form);
    }

    /**
     * 构建测试订单数据
     * 只需传递
     * {
     * 	"payType": "1"
     * }
     * @param payRequestVo
     */
    private void testData(HttpServletRequest request,@RequestBody PayRequestVo payRequestVo) {
        payRequestVo.setRequestUrl(propertyConfigurer.getRequestUrl());
        payRequestVo.setOrderId("TEST" + LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
        payRequestVo.setSubject("测试订单");
        payRequestVo.setTotalPrice("0.01");
        payRequestVo.setIpAddr(getIPaddress(request));
        payRequestVo.setNotifyUrl(getTrueNotifyUrl(payRequestVo.getPayType()));
    }

    @RequestMapping(value = "/alipay-notify", method = RequestMethod.POST)
    public void alipayNotify(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        Map<String, String> params = getAllRequestParam(request, StandardCharsets.UTF_8.toString());
        log.info("支付宝回调的参数为====>" + params);
        if (payService.verifyCallbackHmac(NEWALIPAY, params)) {
            log.info("新版支付宝回调验证成功");
            String trade_status = params.get("trade_status");
            log.info("支付宝回调返回:"+trade_status);
            if (TRADE_SUCCESS.equals(trade_status)) {
                try {
                    PayCallbackVo vo = PayCallbackVo.buildAlipayCallback(params);
                    System.out.println(vo);
                } catch (Exception e) {
                    log.info("支付宝回调成功但是业务发生异常:", e);
                }
            }
        }else {
            log.info("新版支付宝回调验证失败!");
        }
    }


    @RequestMapping(value = "/unionpay-notify", method = RequestMethod.POST)
    public void unionpayNotify(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        Map<String, String> params = getAllRequestParam(request, StandardCharsets.UTF_8.toString());
        log.info("银联回调的参数为====>" + params);
        try {
            if (payService.verifyCallbackHmac(UNIONPAY, params)) {
                PayCallbackVo vo = PayCallbackVo.buildUnionpayCallback(params);
                System.out.println(vo);
                // 请不要修改或删除
                response.getWriter().println("ok");
            } else {
                log.info("银联支付回调验证失败!");
            }
        } catch (IOException e) {
            log.error("银联支付回调失败!" + e.getMessage() + ",回调参数是:" + params, e);
        }
    }

    @RequestMapping(value = "/wxpay-notify", method = RequestMethod.POST)
    public void wxpayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, String> params = XMLUtil.getMapFromInputStreamXML(request.getInputStream(), WXpayClient.INPUT_CHAR_SET);
        log.info("微信支付回调的参数为====>" + params);
        try {
            if (payService.verifyCallbackHmac(WXPAY, params)) {
                PayCallbackVo vo = PayCallbackVo.buildWXpayCallback(params);
                // 请不要修改或删除
                response.getWriter().println("ok");
            }else {
                log.info("微信支付回调验证失败!");
            }
        } catch (Exception e) {
            log.error("微信支付回调失败!,回调参数是:" + params, e);
        }
    }

    @RequestMapping("/returnSuccess")
    public String returnSuccess(){
        return "/pay/paySuccess";
    }

    private String getTrueNotifyUrl(Byte payType) {
        String result = null;
        if (NEWALIPAY.getCode().equals(payType)) {
            result = propertyConfigurer.getAlipayNotifyUrl();
        } else if (UNIONPAY.getCode().equals(payType)) {
            result = propertyConfigurer.getUnionpayNotifyUrl();
        }else if (WXPAY.getCode().equals(payType)) {
            result = propertyConfigurer.getWXpayNotifyUrl();
        }
        return result;
    }

    private static Map<String, String> getAllRequestParam(final HttpServletRequest request, String encoding) throws UnsupportedEncodingException {
        request.setCharacterEncoding(encoding);
        Map<String, String> res = new HashMap<String, String>();
        Enumeration<?> temp = request.getParameterNames();
        if (null != temp) {
            while (temp.hasMoreElements()) {
                String key = (String) temp.nextElement();
                String value = request.getParameter(key);
                if (StringUtils.isNotEmpty(value)) {
                    res.put(key, value);
                }
            }
        }
        return res;
    }

    public static String getIPaddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        } else {
            ip = request.getHeader("Cdn-Src-Ip"); //先取CDN上的IP
            if(StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)){
                return ip;
            }
            ip = request.getHeader("X-Real-IP");
            if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
                return ip;
            }
            return request.getRemoteAddr();
        }
    }
}
